#ifndef LISTA
#define LISTA

#include <iostream>

using namespace std;

template <typename T>
class Double_linked
{
 public:
 	//Nodo
    struct Node
    {
        T data;
        Node* prev;
        Node* next;
        Node(T t, Node* p, Node* n) : data(t), prev(p), next(n) {}
    };

    //punteros a primer y ultimo nodo
    Node* head;
    Node* tail;




	//constructor
    Double_linked() : head( NULL ), tail ( NULL ) {}


    //???
    template<int N>
    Double_linked( T (&arr) [N]) : head( NULL ), tail ( NULL )
    {
        for( int i(0); i != N; ++i)
            push_back(arr[i]);
    }


    bool empty() const { return ( !head || !tail ); }

    operator bool() const { return !empty(); }

    void push_back(T);

    void push_front(T);

    T pop_back();

    T pop_front();

    //borrar, recolocar nodos, devuelve un puntero al nodo movido

    void erase(Node*);

    void pegarAtras(Node*);

    void pegarAdelante(Node*);

    bool unitaria();

    void pegarADerechaDe(Node*, Node*);

    void pegarAIzquierdaDe(Node*, Node*);



    ~Double_linked()
    {
        while(head)
        {
            Node* temp(head);
            head=head->next;
            delete temp;
        }
    }

};

template <typename T>
void Double_linked<T>::push_back(T data)
{
    tail = new Node(data, tail, NULL);
    if( tail->prev )
        tail->prev->next = tail;

    if( empty() )
        head = tail;
}

template <typename T>
void Double_linked<T>::push_front(T data)
{
    head = new Node(data, NULL, head);
    if( head->next )
        head->next->prev = head;

    if( empty() )
        tail = head;
}

template<typename T>
T Double_linked<T>::pop_back()
{
    if( empty() )
        throw("Double_linked : list empty");
    Node* temp(tail);
    T data( tail->data );
    tail = tail->prev ;

    if( tail )
        tail->next = NULL;
    else
        head = NULL ;

    delete temp;
    return data;
}

template<typename T>
T Double_linked<T>::pop_front()
{
    if( empty() )
        throw("Double_linked : list empty");
    Node* temp(head);
    T data( head->data );
    head = head->next ;

    if( head )
        head->prev = NULL;
    else
        tail = NULL;

    delete temp;
    return data;
}


template <typename T>
void Double_linked<T>::erase(Node* n)
{
// cout <<"n->next: " << n->next << endl;
// cout <<"n->prev: " << n->prev << endl;
 if ( n -> next != NULL){ /*cout <<"entre al if " <<endl;*/ ((n->next)->prev) = n -> prev;}
    else {/*cout <<"no entre al if " <<endl;*/ tail = n -> prev;}
   // cout << "segundo if" <<endl;
    if ( n -> prev != NULL){((n->prev)->next) = n -> next;}
    else {head = n -> next;}
   // cout << "CRICRI" <<endl;

    return;
}


template <typename T>
void Double_linked<T>::pegarAtras(Node* n)
{
	n->prev = tail;
	n->next = NULL;

	if(tail!=NULL){tail->next = n;}
	if( empty() ){head=n;}
    tail = n;

    return;


}

template <typename T>
void Double_linked<T>::pegarAdelante(Node* n)
{
 	n->prev = NULL;
	n->next = head;

	if(head!=NULL){head->prev = n;}
	if( empty() ){tail=n;}

    head = n;

    return;
}

template <typename T>
bool Double_linked<T>::unitaria(){

return ((head == tail) && !(empty()));

}



template <typename T>
void Double_linked<T>::pegarADerechaDe(Node* enLista, Node* nuevo){

    nuevo->next = enLista->next;
    nuevo->prev = enLista;
    if(enLista->next!=NULL){enLista->next->prev = nuevo;}
    else{tail=nuevo;}
    enLista->next = nuevo;

}


template <typename T>
void Double_linked<T>::pegarAIzquierdaDe(Node* enLista, Node* nuevo){

    nuevo->prev = enLista->prev;
    nuevo->next = enLista;
    if(enLista->prev!=NULL){enLista->prev->next = nuevo;}
    else{head=nuevo;}
    enLista->prev = nuevo;

}


#endif


//int main()
//{
//    int arr[] = { 4, 6, 8, 32, 19 } ;
//    Double_linked<int> dlist ( arr );
//    dlist.push_back( 11 );
//    dlist.push_front( 100 );
//    while( dlist )
//        std::cout << dlist.pop_back()  << " ";
//}
